package com.desay.pangoo.itmt.service.impl;
import cn.hutool.core.io.unit.DataUnit;
import com.desay.pangoo.common.lite.lang.web.BusinessException;
import com.desay.pangoo.itmt.constants.ContributionConstants;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.desay.pangoo.itmt.controller.vo.contribution.*;
import com.desay.pangoo.itmt.controller.vo.contribution.req.ContributionReqVo;
import com.desay.pangoo.itmt.entity.*;
import com.desay.pangoo.itmt.enums.ExceptionCodeEnum;
import com.desay.pangoo.itmt.enums.ReviewTypeEnum;
import com.desay.pangoo.itmt.repository.*;
import com.desay.pangoo.itmt.service.ContributionLevelService;
import com.desay.pangoo.itmt.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * 贡献度计算服务
 *
 * @author uids1175
 */
@Service
public class ContributionLevelServiceImpl implements ContributionLevelService {


    @Autowired
    private OrgChartRepository orgChartRepository;

    @Autowired
    private TechOnlineReviewRepository techOnlineReviewRepository;

    @Autowired
    private TechOnlineReviewRelevantRepository techOnlineReviewRelevantRepository;

    @Autowired
    private TechOnlineReviewTMTRepository techOnlineReviewTMTRepository;

    @Autowired
    private MemberContributionRepository memberContributionRepository;

    @Autowired
    private ContributionCalRepository contributionCalRepository;



    /**
     * 计算指定日期范围内的贡献度
     *
     * @param
     * @return
     */
    @Override
    public ContributionVo calContributionLevel(DateTime beginTime,DateTime endTime) {
        // 获取全部成员信息 并将其转换为MemberContribution
        List<MemberContribution> memberContributionList = getAllMemberFromOrgChart();
        // 根据参数获取指定范围的TechOnlineReview List
        List<TechOnlineReviewEntity> techOnlineReviewEntityList = getTechOnlineReviewBetween(beginTime, endTime);
        // 根据list中涉及的成员，计算相关成员贡献度。
        ContributionVo contributionVo = calculateContribution(memberContributionList, techOnlineReviewEntityList);
        // 设置日期范围
        contributionVo.setBeginDate(beginTime);
        contributionVo.setEndDate(endTime);
        // 将计算好的贡献度，按照总贡献度从高到低排序。
        CollUtil.sort(contributionVo.getMemberContributionLelvelList(), (c1, c2) ->
                Double.compare(c2.getTotalContribution().doubleValue(), c1.getTotalContribution().doubleValue()));
        return contributionVo;
    }

    /**
     * 利用提案Id，计算对应提案的贡献度，并分配给其他成员。
     * @param reviewId
     */
    @Override
    public void addContribution(Long reviewId) {
        // 判断提案是否存在
        TechOnlineReviewEntity reviewEntity = techOnlineReviewRepository.findById(reviewId)
                .orElseThrow(() -> new BusinessException(ExceptionCodeEnum.TECH_ONLINE_REVIEW_NOT_EXIST));


        // 判断提案流程是否结束
        if (reviewEntity.getReviewResult() == null) {
            throw new BusinessException(ExceptionCodeEnum.TECH_ONLINE_ITMT_REVIEW_RESULT_CATNOT_EMPTY);
        }

        // 判断这个提案是否计算过
        ContributionCalEntity contributionCal = contributionCalRepository.findByReviewId(reviewId);
        if (contributionCal != null) {
            throw new BusinessException(ExceptionCodeEnum.REVIEW_HAS_CALCULATION);
        }

        // 该提案是否本月创建
        DateTime createTime = cn.hutool.core.date.DateUtil.date(reviewEntity.getCreateTime());
        DateTime now = cn.hutool.core.date.DateUtil.date();
        if (createTime.month() != now.month()) {
            throw new BusinessException(ExceptionCodeEnum.REVIEW_HAS_CALCULATION);
        }


        // 计算这个提案能够提供的贡献度
        // 获取与这个提案有关的全部成员信息，并转换为MemberContribution对象
        List<MemberContribution> memberList = createMemberContributionByReview(reviewEntity);
        // 计算这个提案在创建阶段和评审阶段提供的贡献度
        DateTime beginDate = DateUtil.getBeginDateTime(now.toDateStr());
        DateTime endDate = DateUtil.getEndDateTime(now.toDateStr());
        List<TechOnlineReviewEntity> allReviewEntity = techOnlineReviewRepository
                .findAllByCreateTimeBetween(beginDate,endDate);

        calculateCreationContribution(memberList,reviewEntity,allReviewEntity,getProposalQuality(reviewEntity));
        calculateReviewContribution(memberList,reviewEntity,getProposalQuality(reviewEntity));
        calculateTotalContribution(memberList);


        // 将计算好的贡献度，持久化到每月贡献度中
        Set<String> nickNames = memberList.stream().map(MemberContribution::getNickName).collect(Collectors.toSet());
        List<MemberContributionEntity> memberContributionEntityList = memberContributionRepository
                .findByDateRangeAndNickNames(beginDate, endDate, nickNames);

        Map<String, MemberContributionEntity> memberContributionEntityMap = memberContributionEntityList.stream().collect(Collectors.toMap(MemberContributionEntity::getNickName, Function.identity()));

        // 批量保存数据
        List<MemberContributionEntity> needSaveMemberContributionList = new ArrayList<>();
        for (MemberContribution memberContribution : memberList) {
            MemberContributionEntity needSaveEntity = memberContributionEntityMap.getOrDefault(memberContribution.getNickName(), new MemberContributionEntity());
            // 相关的贡献度数据填充到needSaveEntity中，并加入到集合needSaveMemberContributionList中
            needSaveEntity = injectContributionVal(memberContribution,needSaveEntity);
            needSaveMemberContributionList.add(needSaveEntity);
        }
        memberContributionRepository.saveAll(needSaveMemberContributionList);

        // 新增额外一条记录，标识这个提案的贡献度已经被计算，不参与每月的贡献度批量计算
        ContributionCalEntity contributionCalEntity = new ContributionCalEntity();
        contributionCalEntity.setReviewId(reviewId);
        contributionCalEntity.setCalDate(cn.hutool.core.date.DateUtil.date());

        contributionCalRepository.save(contributionCalEntity);

    }

    /**
     * 获取和这个提案相关的全部成员信息
     * @param reviewEntity
     * @return
     */
    private List<MemberContribution> createMemberContributionByReview(TechOnlineReviewEntity reviewEntity) {
        List<TechOnlineReviewRelevantEntity> relevantEntityList = techOnlineReviewRelevantRepository.findByTechOnlineReview(reviewEntity);
        List<TechOnlineReviewTMTEntity> reviewTMTEntityList = techOnlineReviewTMTRepository.findByTechOnlineReview(reviewEntity);
        Set<String> nickNames = relevantEntityList.stream().map(TechOnlineReviewRelevantEntity::getCreatorName).collect(Collectors.toSet());
        nickNames.addAll(reviewTMTEntityList.stream().map(TechOnlineReviewTMTEntity::getTmtFullUser).collect(Collectors.toSet()));

        return nickNames.stream().map(name -> MemberContribution.builder()
                .creationPhaseContribution(new CreationPhaseContribution())
                .reviewPhaseContribution(new ReviewPhaseContribution())
                .nickName(name)
                .totalContribution(BigDecimal.ZERO)
                .build()).toList();
    }

    /**
     * 将memberContribution计算好的贡献度注入到needSaveEntity中
     * @param memberContribution
     * @param needSaveEntity
     * @return
     */
    private MemberContributionEntity injectContributionVal(MemberContribution memberContribution, MemberContributionEntity needSaveEntity) {
        needSaveEntity.setNickName(memberContribution.getNickName());
        needSaveEntity.setDate(DateUtil.getBeginDateTime(cn.hutool.core.date.DateUtil.date().toDateStr()));
        needSaveEntity.setTotalContribution(memberContribution.getTotalContribution());
        needSaveEntity.setTechPlanReview(memberContribution.getCreationPhaseContribution().getTechPlanReview());
        needSaveEntity.setTechDefReview(memberContribution.getCreationPhaseContribution().getTechDefReview());
        needSaveEntity.setTechDelReview(memberContribution.getCreationPhaseContribution().getTechDelReview());
        needSaveEntity.setRelevantConfirm(memberContribution.getReviewPhaseContribution().getRelevantConfirm());
        needSaveEntity.setAttendMeeting(memberContribution.getReviewPhaseContribution().getAttendMeeting());
        needSaveEntity.setAudit(memberContribution.getReviewPhaseContribution().getAudit());
        needSaveEntity.setComment(memberContribution.getReviewPhaseContribution().getComment());
        return needSaveEntity;

    }


    /**
     * 从数据库中获取已经持久化了的贡献数据
     *
     * @param vo
     * @return
     */
    @Override
    public ContributionVo getContributionLevel(ContributionReqVo vo) {
        String beginDate = vo.getBeginDate();
        String endDate = vo.getEndDate();

        //获取指定时间范围内的每月贡献度记录
        DateTime beginDateTime = DateUtil.getBeginDateTime(beginDate);
        DateTime endDateTime = DateUtil.getEndDateTime(endDate);
        Collection<MemberContributionEntity> allContributionEntity =
                memberContributionRepository.findAllByDateBetween(beginDateTime, endDateTime);
        /**
         * 部分领导层不参加贡献度统计
         * 组织角色:ITMT ChairMan:1，ITMT Leader:2，ITMT
         * SubLeader:3，ITMT成员:4,TSP:5,PRG: 6,秘书长：7，委员：8,统筹人：9,PLTMT leader：10,
         */
        List<Integer> org_roles = Arrays.asList(1, 5, 6, 7, 8, 9);  // 按照枚举类添加成员
        List<String> except_members = orgChartRepository.findByOrgRoleIn(org_roles).stream().map(OrgChartEntity::getNickName).collect(Collectors.toList());
    
        // 按照nickName对贡献度分组
        Map<String, List<MemberContributionEntity>> contributionMap = allContributionEntity.stream().filter(item -> !except_members.contains(item.getNickName()))
                .collect(Collectors.groupingBy(MemberContributionEntity::getNickName));

        // 整合数据，创建MemberContribution对象
        List<MemberContribution> resList = contributionMap.keySet().stream().map(name -> {
            List<MemberContributionEntity> list = contributionMap.get(name);
            MemberContribution memberContribution = createMemberContribution(list);
            memberContribution.setNickName(name);
            return memberContribution;
        }).sorted((m1, m2) -> Double.compare(m2.getTotalContribution().doubleValue(),
                m1.getTotalContribution().doubleValue())).collect(Collectors.toList());

        ContributionVo contributionVo = new ContributionVo();
        contributionVo.setBeginDate(beginDateTime);
        contributionVo.setEndDate(endDateTime);
        contributionVo.setMemberContributionLelvelList(resList);
        return contributionVo;
    }


    /**
     * 获取数据库中存在的最大日期
     * @return
     */
    @Override
    public DateTime getExistedMaxDate() {
        MemberContributionEntity entity = memberContributionRepository.findTopByOrderByDateDesc();
        if (entity == null) {
            return cn.hutool.core.date.DateUtil.date();
        }
        return cn.hutool.core.date.DateUtil.date(entity.getDate());
    }

    /**
     * 获取目前贡献度支持检索的日期范围
     * @return
     */
    @Override
    public ContributionDateRange getContributionDateRange() {
        MemberContributionEntity minEntity = memberContributionRepository.findTopByOrderByDateAsc();
        MemberContributionEntity maxEntity = memberContributionRepository.findTopByOrderByDateDesc();
        return ContributionDateRange.builder()
                .minDate(cn.hutool.core.date.DateUtil.date(minEntity.getDate()))
                .maxDate(cn.hutool.core.date.DateUtil.date(maxEntity.getDate()))
                .build();
    }

    /**
     * 持久化MemberContributionEntity列表
     * @param list
     */
    @Override
    public void saveAll(List<MemberContributionEntity> list) {
        memberContributionRepository.saveAll(list);
    }

    /**
     * 每月一次贡献度计算并持久化
     */
    @Override
    public void calContributionPreMonth(DateTime date) {
        // 判断上个月的贡献度是否已经计算
        long existMemberContribution = memberContributionRepository.countByDate(date);
        long memberNums = orgChartRepository.countDistinctByNickName();
        if (existMemberContribution == memberNums) {
            return;
        }
        // 如果全体成员的贡献度没有全部记录完毕，计算没有计算的提案贡献度
        String dateStr = date.toDateStr();
        ContributionVo contributionLevel = calContributionLevel(com.desay.pangoo.itmt.utils.DateUtil.getBeginDateTime(dateStr), DateUtil.getEndDateTime(dateStr));
        List<MemberContribution> memberContributionLelvelList = contributionLevel.getMemberContributionLelvelList();
        List<MemberContribution> needSaveMemberContribution = memberContributionLelvelList.stream().toList();

        // 转换对象，持久化数据
        // 获取期间已经持久化来的数据
        Collection<MemberContributionEntity> savedMemberContribution = memberContributionRepository.findAllByDateBetween(DateUtil.getBeginDateTime(dateStr), DateUtil.getEndDateTime(dateStr));
        Map<String, MemberContributionEntity> savedMemberContributionMap = savedMemberContribution.stream().collect(Collectors.toMap(MemberContributionEntity::getNickName, Function.identity()));

        // 更新存在的成员的贡献度，添加不存在的成员的贡献度
        List<MemberContributionEntity> memberContributionEntityList = new ArrayList<>();
        for (MemberContribution item : needSaveMemberContribution) {
            MemberContributionEntity entity = savedMemberContributionMap.getOrDefault(item.getNickName(),
                    new MemberContributionEntity());
            entity.setNickName(item.getNickName());
            entity.setDate(contributionLevel.getBeginDate());
            entity.setTotalContribution(item.getTotalContribution());
            entity.setTechPlanReview(item.getCreationPhaseContribution().getTechPlanReview());
            entity.setTechDefReview(item.getCreationPhaseContribution().getTechDefReview());
            entity.setTechDelReview(item.getCreationPhaseContribution().getTechDelReview());
            entity.setRelevantConfirm(item.getReviewPhaseContribution().getRelevantConfirm());
            entity.setAttendMeeting(item.getReviewPhaseContribution().getAttendMeeting());
            entity.setAudit(item.getReviewPhaseContribution().getAudit());
            entity.setComment(item.getReviewPhaseContribution().getComment());
            memberContributionEntityList.add(entity);
        }

        // 批量保存
        saveAll(memberContributionEntityList);
    }

    private MemberContribution createMemberContribution(List<MemberContributionEntity> list) {
        MemberContribution memberContribution = new MemberContribution();
        CreationPhaseContribution creationPhaseContribution = new CreationPhaseContribution();
        ReviewPhaseContribution reviewPhaseContribution = new ReviewPhaseContribution();
        memberContribution.setCreationPhaseContribution(creationPhaseContribution);
        memberContribution.setReviewPhaseContribution(reviewPhaseContribution);

        // 求和
        double totalTechPlanReview = list.stream().map(item -> item.getTechPlanReview().doubleValue()).mapToDouble(item -> item).sum();
        double totalTechDefReview = list.stream().map(item -> item.getTechDefReview().doubleValue()).mapToDouble(item -> item).sum();
        double totalTechDelReview = list.stream().map(item -> item.getTechDelReview().doubleValue()).mapToDouble(item -> item).sum();
        double totalRelevantConfirm = list.stream().map(item -> item.getRelevantConfirm().doubleValue()).mapToDouble(item -> item).sum();
        double totalAttendMeeting = list.stream().map(item -> item.getAttendMeeting().doubleValue()).mapToDouble(item -> item).sum();
        double totalAudit = list.stream().map(item -> item.getAudit().doubleValue()).mapToDouble(item -> item).sum();
        double totalComment = list.stream().map(item -> item.getComment().doubleValue()).mapToDouble(item -> item).sum();
        double sumTotalContribution = list.stream().map(item -> item.getTotalContribution().doubleValue()).mapToDouble(item -> item).sum();

        creationPhaseContribution.setTechPlanReview(BigDecimal.valueOf(totalTechPlanReview));
        creationPhaseContribution.setTechDefReview(BigDecimal.valueOf(totalTechDefReview));
        creationPhaseContribution.setTechDelReview(BigDecimal.valueOf(totalTechDelReview));

        reviewPhaseContribution.setRelevantConfirm(BigDecimal.valueOf(totalRelevantConfirm));
        reviewPhaseContribution.setAttendMeeting(BigDecimal.valueOf(totalAttendMeeting));
        reviewPhaseContribution.setAudit(BigDecimal.valueOf(totalAudit));
        reviewPhaseContribution.setComment(BigDecimal.valueOf(totalComment));

        memberContribution.setTotalContribution(BigDecimal.valueOf(sumTotalContribution));

        return memberContribution;
    }


    /**
     * 计算 techOnlineReviewEntityList中评审能够提供的贡献度并分配给memberContributionList中的相关成员
     *
     * @param memberContributionList     ITMT全部成员列表
     * @param techOnlineReviewEntityList 一段日期返回内的评审列表
     * @return 贡献度信息 只有成员贡献度信息，不包含日期范围信息
     */
    private ContributionVo calculateContribution(List<MemberContribution> memberContributionList, List<TechOnlineReviewEntity> techOnlineReviewEntityList) {
        for (TechOnlineReviewEntity reviewEntity : techOnlineReviewEntityList) {
            // 计算这个提案质量 提案的相关域 / 总工作域(18)
            BigDecimal proposalQuality = getProposalQuality(reviewEntity);
            // 计算一个提案创建阶段能够提供的贡献度并分配给相关成员
            calculateCreationContribution(memberContributionList, reviewEntity, techOnlineReviewEntityList, proposalQuality);
            // 计算一个提案评审阶段能够提案的贡献度并分配给相关成员
            calculateReviewContribution(memberContributionList, reviewEntity, proposalQuality);
        }

        // 计算成员的总贡献度
        calculateTotalContribution(memberContributionList);

        return ContributionVo.builder().memberContributionLelvelList(memberContributionList).build();

    }


    /**
     * 计算每个成员总的贡献度
     *
     * @param memberContributionList 成员列表
     */
    private void calculateTotalContribution(List<MemberContribution> memberContributionList) {
        for (MemberContribution memberContribution : memberContributionList) {
            CreationPhaseContribution creationPhaseContribution = memberContribution.getCreationPhaseContribution();
            ReviewPhaseContribution reviewPhaseContribution = memberContribution.getReviewPhaseContribution();
            BigDecimal total = BigDecimal.valueOf(0);
            total = creationPhaseContribution.getTechDefReview().add(creationPhaseContribution.getTechDelReview()).add(creationPhaseContribution.getTechPlanReview());
            total = total.add(reviewPhaseContribution.getAttendMeeting()).add(reviewPhaseContribution.getRelevantConfirm()).add(reviewPhaseContribution.getAudit()).add(reviewPhaseContribution.getComment());
            memberContribution.setTotalContribution(total);
        }
    }


    /**
     * 计算评审阶段的贡献度
     *
     * @param memberContributionList 成员列表
     * @param reviewEntity           一个提案
     */
    private void calculateReviewContribution(List<MemberContribution> memberContributionList, TechOnlineReviewEntity reviewEntity, BigDecimal proposalQuality) {
        // 获取相关性反馈列表
        List<TechOnlineReviewRelevantEntity> relevantEntityList = getRelevantEntityListByReview(reviewEntity);

        // 计算这个提案的相关性确认的贡献度(0.02)，并分配给相关的成员
        BigDecimal relevantContributionWeight = BigDecimal.valueOf(ContributionConstants.RELEVANT_WEIGHT);
        BigDecimal reviewWeight = BigDecimal.valueOf(ContributionConstants.REVIEW_WEIGHT);

        // 筛选确认过相关性反馈的成员
        relevantEntityList = relevantEntityList.stream().filter(entity -> (entity.getIsRelevant() != null && entity.getAuditOrNot() == null) || (entity.getIsRelevant() == null && entity.getAuditOrNot() != null)).toList();

        //  给对应的成员分配贡献度
        Set<String> memberSet = relevantEntityList.stream().map(TechOnlineReviewRelevantEntity::getCreatorName).collect(Collectors.toSet());

        memberContributionList.stream().filter(member -> memberSet.contains(member.getNickName())).forEach(memberContribution -> {
            ReviewPhaseContribution reviewPhaseContribution = memberContribution.getReviewPhaseContribution();
            BigDecimal val = relevantContributionWeight.multiply(reviewWeight).multiply(proposalQuality);
            BigDecimal relevantConfirm = reviewPhaseContribution.getRelevantConfirm();
            reviewPhaseContribution.setRelevantConfirm(relevantConfirm.add(val));
        });

        // 获取TMT参会成员信息列表
        List<TechOnlineReviewTMTEntity> reviewTMTEntityList = getReviewTMTEntityByReview(reviewEntity);

        // 根据TMT信息列表，计算参会贡献度，旁听贡献度，评论贡献度

        // 过滤reviewTMTEntityList，获取实际参会的人员信息
        reviewTMTEntityList = reviewTMTEntityList.stream().filter(tmtEntity -> (tmtEntity.getIsParticipate() != null && tmtEntity.getJudgesType() == 1) || tmtEntity.getJudgesType() == 2).collect(Collectors.toList());


        Map<String, MemberContribution> memberMap = memberContributionList.stream().collect(Collectors.toMap(MemberContribution::getNickName, Function.identity()));
        // 计算参会/旁听成员的贡献度
        for (TechOnlineReviewTMTEntity tmtEntity : reviewTMTEntityList) {
            String tmtFullUser = tmtEntity.getTmtFullUser();
            MemberContribution memberContribution = memberMap.get(tmtFullUser);
            if (memberContribution == null) {
                continue;
            }
            ReviewPhaseContribution reviewPhaseContribution = memberContribution.getReviewPhaseContribution();

            // 计算参会贡献度
            if (tmtEntity.getJudgesType() == 1) {
                BigDecimal weight = BigDecimal.valueOf(ContributionConstants.ATTEND_WEIGHT);
                BigDecimal attendMeeting = reviewPhaseContribution.getAttendMeeting();
                BigDecimal val = proposalQuality.multiply(weight).multiply(reviewWeight);
                reviewPhaseContribution.setAttendMeeting(attendMeeting.add(val));
            }

            // 计算旁听贡献度
            if (tmtEntity.getJudgesType() == 2) {
                BigDecimal weight = BigDecimal.valueOf(ContributionConstants.AUDIT_WEIGHT);
                BigDecimal audit = reviewPhaseContribution.getAudit();
                BigDecimal val = proposalQuality.multiply(weight).multiply(reviewWeight);
                reviewPhaseContribution.setAudit(audit.add(val));
            }

            // 计算评论贡献度
            if (!StrUtil.isEmpty(tmtEntity.getReviewContent())) {
                BigDecimal weight = BigDecimal.valueOf(ContributionConstants.COMMENT_WEIGHT);
                BigDecimal comment = reviewPhaseContribution.getComment();
                BigDecimal val = proposalQuality.multiply(weight).multiply(reviewWeight);
                reviewPhaseContribution.setComment(comment.add(val));
            }
        }


    }

    private List<TechOnlineReviewRelevantEntity> getRelevantEntityListByReview(TechOnlineReviewEntity reviewEntity) {
        return techOnlineReviewRelevantRepository.findByTechOnlineReview(reviewEntity);
    }

    private List<TechOnlineReviewTMTEntity> getReviewTMTEntityByReview(TechOnlineReviewEntity reviewEntity) {
        return techOnlineReviewTMTRepository.findByTechOnlineReview(reviewEntity);
    }

    /**
     * 计算一个提案创建阶段能提供的贡献度，并分配给相关的成员
     *
     * @param memberContributionList 全部成员
     * @param reviewEntity           一个评审
     */
    private void calculateCreationContribution(List<MemberContribution> memberContributionList,
                                               TechOnlineReviewEntity reviewEntity,
                                               List<TechOnlineReviewEntity> techOnlineReviewEntityList,
                                               BigDecimal proposalQuality) {
        // 贡献度计算：提案质量 + 颠覆性技术权重 + 跨域性技术权重 + 通过率的一个分量（通过率/（2*这个成员的总提案数））

        BigDecimal contributionVal = proposalQuality.add(getCrossContribution(reviewEntity))
                .add(getDisruptiveContribution(reviewEntity)).add(getPassRateWeight(reviewEntity, techOnlineReviewEntityList));
        // 根据不同的提案类型，分配不同的权重并更新贡献度
        BigDecimal creationWeight = BigDecimal.valueOf(ContributionConstants.CREATION_WEIGHT);
        contributionVal = contributionVal.multiply(getProposalTypeWeight(reviewEntity)).multiply(creationWeight);

        // 找到对应的成员，更新其贡献度
        MemberContribution memberContribution = memberContributionList.stream().filter(member ->
                member.getNickName().equals(reviewEntity.getCreator())).findFirst().orElse(null);

        // 找不到这个成员信息，就不计算其贡献度
        if (memberContribution == null) {
            return;
        }

        // 更新贡献度
        updateMemberCreationContribution(memberContribution, contributionVal, reviewEntity.getReviewType());

        // 由于创建提案的人必参会，所以这里需要额外加一个参会贡献度
        BigDecimal weight = BigDecimal.valueOf(ContributionConstants.ATTEND_WEIGHT);
        BigDecimal reviewWeight = BigDecimal.valueOf(ContributionConstants.REVIEW_WEIGHT);
        ReviewPhaseContribution reviewPhaseContribution = memberContribution.getReviewPhaseContribution();
        BigDecimal attendMeeting = reviewPhaseContribution.getAttendMeeting();
        BigDecimal val = proposalQuality.multiply(weight).multiply(reviewWeight);
        reviewPhaseContribution.setAttendMeeting(attendMeeting.add(val));

    }

    /**
     * 更新贡献度
     *
     * @param memberContribution 对应的成员
     * @param contributionVal    能够提供的贡献度值
     * @param reviewType         提案类型
     */
    private void updateMemberCreationContribution(MemberContribution memberContribution, BigDecimal contributionVal, Integer reviewType) {
        ReviewTypeEnum typeEnum = ReviewTypeEnum.convent(reviewType);
        CreationPhaseContribution creationPhaseContribution = memberContribution.getCreationPhaseContribution();
        if (typeEnum == ReviewTypeEnum.TECH_PLAN) {
            BigDecimal techPlanReview = creationPhaseContribution.getTechPlanReview();
            creationPhaseContribution.setTechPlanReview(techPlanReview.add(contributionVal));
        } else if (typeEnum == ReviewTypeEnum.TECH_DEF) {
            BigDecimal techDefReview = creationPhaseContribution.getTechDefReview();
            creationPhaseContribution.setTechDefReview(techDefReview.add(contributionVal));
        } else if (typeEnum == ReviewTypeEnum.TECH_DEL) {
            BigDecimal techDelReview = creationPhaseContribution.getTechDelReview();
            creationPhaseContribution.setTechDelReview(techDelReview.add(contributionVal));
        }
    }

    /**
     * 根据不同的提案类型返回不同的权重
     *
     * @param reviewEntity 提案信息
     * @return 对应的权重
     */
    private BigDecimal getProposalTypeWeight(TechOnlineReviewEntity reviewEntity) {
        Integer reviewType = reviewEntity.getReviewType();
        ReviewTypeEnum typeEnum = ReviewTypeEnum.convent(reviewType);
        return BigDecimal.valueOf(typeEnum.getWeight());
    }

    /**
     * 获取到这个成员通过率的一个分量 通过率/(2*这个成员的总提案数)
     *
     * @param reviewEntity 提案
     * @return 通过率的一个分量
     */
    private BigDecimal getPassRateWeight(TechOnlineReviewEntity reviewEntity, List<TechOnlineReviewEntity> techOnlineReviewEntityList) {
        List<TechOnlineReviewEntity> reviewEntityList = techOnlineReviewEntityList.stream().filter(entity -> entity.getCreator().equals(reviewEntity.getCreator())).collect(Collectors.toList());
        // 获取通过提案数
        long count = reviewEntityList.stream().filter(TechOnlineReviewEntity::getReviewResult).count();

        // 总提案数
        int sum = reviewEntityList.size();

        BigDecimal countDecimal = BigDecimal.valueOf(count);
        BigDecimal sumDecimal = BigDecimal.valueOf(sum);
        BigDecimal passRate = countDecimal.divide(sumDecimal, RoundingMode.HALF_UP);
        BigDecimal base = BigDecimal.valueOf(2).multiply(sumDecimal);
        return passRate.divide(base, RoundingMode.HALF_UP).setScale(6, RoundingMode.HALF_UP);
    }

    /**
     * 获取到颠覆性技术的贡献度
     *
     * @param reviewEntity 一个提案
     * @return 颠覆性性技术的贡献度
     */
    private BigDecimal getDisruptiveContribution(TechOnlineReviewEntity reviewEntity) {
        if (reviewEntity.getDisruptiveReview() != null && reviewEntity.getDisruptiveReview() > 6) {
            return BigDecimal.valueOf(ContributionConstants.DISRUPTIVE_CONTRIBUTION);
        }
        return BigDecimal.ZERO;
    }

    /**
     * 获取跨域性技术的贡献度
     *
     * @param reviewEntity 一个提案
     * @return 跨域性技术的贡献度
     */
    private BigDecimal getCrossContribution(TechOnlineReviewEntity reviewEntity) {
        if (reviewEntity.getIsCrossReview() != null && reviewEntity.getIsCrossReview()) {
            return BigDecimal.valueOf(ContributionConstants.CROSS_CONTRIBUTION);
        }
        return BigDecimal.ZERO;
    }


    /**
     * 获取提案质量 提案的相关域 / 总工作域(18)
     *
     * @param reviewEntity 一个技术提案
     * @return 提案质量
     */
    private BigDecimal getProposalQuality(TechOnlineReviewEntity reviewEntity) {
        List<TechOnlineReviewRelevantEntity> relevantList = techOnlineReviewRelevantRepository.findByTechOnlineReview(reviewEntity);

        long relevantCount = relevantList.stream().filter(relevantEntity -> relevantEntity.getIsRelevant()
                != null && relevantEntity.getIsRelevant()).count();

        BigDecimal relevantCountDecimal = BigDecimal.valueOf(relevantCount);
        BigDecimal totalCountDecimal = BigDecimal.valueOf(ContributionConstants.TOTAL_TMT);
        return relevantCountDecimal.divide(totalCountDecimal, 6,RoundingMode.HALF_UP).setScale(6, RoundingMode.HALF_UP)
                .add(getDisruptiveContribution(reviewEntity)).add(getCrossContribution(reviewEntity));
    }

    /**
     * 根据指定的日期返回，获取对应的日期的评审
     *
     * @param beginDate 开始日期
     * @param endDate   结束日期
     * @return 对应日期的评审列表（评审需要是结束状态）
     */
    private List<TechOnlineReviewEntity> getTechOnlineReviewBetween(DateTime beginDate, DateTime endDate) {

        // 获取全部提案
        List<TechOnlineReviewEntity> techOnlineReviewEntityList = techOnlineReviewRepository.findAllByCreateTimeBetween(beginDate, endDate);

        // 已经计算过的提案
        List<ContributionCalEntity> contributionCalEntityList = contributionCalRepository.findAllByCalDateBetween(beginDate,endDate);
        Set<Long> reviewIdSet = contributionCalEntityList.stream().map(ContributionCalEntity::getReviewId).collect(Collectors.toSet());

        // 排除计算过的提案，以及提案流程没有结束的提案
        return techOnlineReviewEntityList.stream().filter(reviewEntity -> !reviewIdSet.contains(reviewEntity.getId())).filter(review -> review.getReviewResult() != null).toList();

    }

    /**
     * 从组织架构中获取全部成员信息
     *
     * @return MemberContribution列表，只包含nickName信息
     */
    private List<MemberContribution> getAllMemberFromOrgChart() {
        /**
         * 部分领导层不参加贡献度统计
         * 组织角色:ITMT ChairMan:1，ITMT Leader:2，ITMT
         * SubLeader:3，ITMT成员:4,TSP:5,PRG: 6,秘书长：7，委员：8,统筹人：9,PLTMT leader：10,
         */
        List<Integer> org_roles = Arrays.asList(2, 3, 4, 10);  // 按照枚举类添加成员
        Iterable<OrgChartEntity> allMembers = orgChartRepository.findByOrgRoleIn(org_roles);

        // 保证成员的唯一性
        List<OrgChartEntity> distinctAllMembers = StreamSupport.stream(allMembers.spliterator(), false)
                .collect(Collectors.toMap(OrgChartEntity::getNickName, Function.identity(), (o1, o2) -> o1)).values().stream().toList();

        // 初始化MemberContribution
        return distinctAllMembers.stream().map(member -> MemberContribution.builder().nickName(member.getNickName())
                .creationPhaseContribution(new CreationPhaseContribution())
                .reviewPhaseContribution(new ReviewPhaseContribution()).build()).collect(Collectors.toList());

    }
}
